﻿namespace MakeVSProject4FFmpeg
{
    #region using directives

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Text;
    #endregion

    enum FileType
    {
        CFile,
        AsmFile,
        HeaderFile
    }

    [DebuggerDisplay("filename = {FullPath}")]
    class CompilationUnit
    {
        private static int objPrefixCounter = 0;

        private string fileName;

        private FileType fileType;

        private bool excludeFromBuild;

        private bool mustTweakObjFileName;

        private string prefixObjectFileName;

        private string additionalIncludeDirectories;

        private string additionalPreprocessorDefinitions;

        private List<string> excludeFromBuildWithCondition;

        // tuple: nodeName, condition, value
        private List<Tuple<string, string, string>> nodeConditionValueList;

        public CompilationUnit(string fileName, FileType type)
            : this(fileName, type, false)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CompilationUnit"/> class.
        /// </summary>
        /// <param name="fileName">Name of the file.</param>
        /// <param name="type">The type.</param>
        /// <param name="excludeFromBuild">If set to <c>true</c> the file will be marked (unconditionally) to be excluded from the build.</param>
        public CompilationUnit(string fileName, FileType type, bool excludeFromBuild)
            : this(fileName, type, excludeFromBuild, null, null, null)
        {
        }

        public CompilationUnit(string fileName, FileType type, bool excludeFromBuild, string prefixObjectFileName, string additionalIncludeDirectories, string additionalPreprocessorDefinitions)
        {
            this.fileName = fileName;
            this.fileType = type;
            this.excludeFromBuild = excludeFromBuild;
            this.prefixObjectFileName = prefixObjectFileName;
            this.additionalIncludeDirectories = additionalIncludeDirectories;
            this.additionalPreprocessorDefinitions = additionalPreprocessorDefinitions;
        }

        public void AddExcludeFromCompilationWithCondition(string condition)
        {
            if (this.excludeFromBuildWithCondition == null)
            {
                this.excludeFromBuildWithCondition = new List<string>();
            }

            this.excludeFromBuildWithCondition.Add(condition);
        }

        /// <summary>
        /// The information added here will end up in a node below the "compile"-directive
        /// in the project, something like this:
        /// &lt;Defines Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"&gt;ARCH_X86_64=0;HIGH_BIT_DEPTH =0;BIT_DEPTH=8;WIN32=1;PREFIX&lt;/Defines&gt;
        /// In this example we have node="Defines", condition=""'$(Configuration)|$(Platform)'=='De...." and value="ARCH_X86_64=0;HIGH_BIT..."
        /// </summary>
        /// <param name="node">The node.</param>
        /// <param name="condition">The condition.</param>
        /// <param name="value">The value.</param>
        public void AddNodeConditionValue(string node, string condition, string value)
        {
            if (this.nodeConditionValueList == null)
            {
                this.nodeConditionValueList = new List<Tuple<string, string, string>>();
            }

            this.nodeConditionValueList.Add(new Tuple<string, string, string>(node, condition, value));
        }

        public FileType Type
        {
            get { return this.fileType; }
        }

        public bool ExcludeFromBuild
        {
            get { return this.excludeFromBuild; }
            set { this.excludeFromBuild = value; }
        }

        public string FileNameWithoutExtension
        {
            get { return Path.GetFileNameWithoutExtension(this.fileName); }
        }

        public string AdditionalIncludeDirectories
        {
            get { return this.additionalIncludeDirectories; }
            set { this.additionalIncludeDirectories = value; }
        }

        public string AdditionalPreprocessorDefinitions
        {
            get { return this.additionalPreprocessorDefinitions; }
        }

        public string FullPath
        {
            get { return this.fileName; }
        }

        public string PathWithoutFileName
        {
            get
            {
                int index = this.fileName.LastIndexOf('/');
                if (index < 0)
                {
                    return string.Empty;
                }

                string s = this.fileName.Substring(0, index);
                if (s.StartsWith("./"))
                {
                    return s.Substring(2);
                }
                else if (string.CompareOrdinal(s, ".") == 0)
                {
                    return string.Empty;
                }
                else
                {
                    return s;
                }
            }
        }

        public bool MustTweakObjFileName
        {
            get { return this.mustTweakObjFileName; }
            set { this.mustTweakObjFileName = value; }
        }

        public bool HasExcludeFromBuildWithCondition
        {
            get { return this.excludeFromBuildWithCondition != null; }
        }

        public IEnumerable<string> ExcludeFromBuildWithCondition
        {
            get { return this.excludeFromBuildWithCondition ?? Enumerable.Empty<string>(); }
        }

        public bool HasNodeConditionValueList
        {
            get { return this.nodeConditionValueList != null; }
        }

        public IEnumerable<Tuple<string, string, string>> NodeConditionValueList
        {
            get { return this.nodeConditionValueList ?? Enumerable.Empty<Tuple<string, string, string>>(); }
        }

        public string GetProjectRelativeFilename()
        {
            return this.fileName;
        }

        public string GetProjectRelativeFilenameWithBackSlash()
        {
            return this.fileName.Replace('/', '\\');
        }

        public string GetProjectRelativeFilenameWithForwardSlash()
        {
            return this.fileName.Replace('\\', '/');
        }

        public string GetObjectFilenamePrefix()
        {
            if (!string.IsNullOrEmpty(this.prefixObjectFileName))
            {
                return this.prefixObjectFileName;
            }

            if (this.FullPath.Count(c => c == '/') >= 1)
            {
                StringBuilder sb = new StringBuilder();
                int slashCount = 0;
                foreach (char ch in this.FullPath.Reverse())
                {
                    if (slashCount == 0 && ch == '/')
                    {
                        slashCount = 1;
                    }
                    else if (slashCount == 1 && ch != '/')
                    {
                        sb.Append(ch);
                    }
                    else if (slashCount == 1 && ch == '/')
                    {
                        break;
                    }
                }

                if (sb.Length > 0)
                {
                    return new string(sb.ToString().Reverse().ToArray());
                }
            }

            string str = objPrefixCounter.ToString(CultureInfo.InvariantCulture);
            objPrefixCounter++;
            return str;
        }
    }
}
